<?php
/**
 * 对提交文件进行检查
 *
 * @author Zeon <scplay@gmail.com>
 * @date 2018/6/14
 * @copyright PanxSoft Inc.
 */
namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;
use Illuminate\Http\UploadedFile;

/**
 * Class ImageFile
 *
 * @example
 *  (new ImageFile(false))->limitSize(2048)->limitExtension(['png', 'jpg', 'pdf'])
 *
 * @package App\Rules
 */
class ImageFile implements Rule
{
    const VALIDATION_LOCALE_KEY = 'validation.image_file';

    /**
     * @var string
     */
    protected $attribute;

    /**
     * @var int
     */
    protected $limit_size;

    /**
     * @var array
     */
    protected $limit_extensions;

    /**
     * @var array
     */
    protected $except_extensions;


    /**
     * Determine if the validation rule passes.
     *
     * @param  string $attribute
     * @param  mixed $value
     * @return bool
     */
    public function passes($attribute, $value)
    {
        $this->attribute = $attribute;

        if ($value instanceof UploadedFile) {
            if ($this->limit_size && ! $this->isFileSizeInLimit($value)) {
                return false;
            }

            if ($this->limit_extensions && ! $this->isFileTypeInLimit($value)) {
                return false;
            }

            if ($this->except_extensions && $this->isFileTypeInExcept($value)) {
                return false;
            }

            return true;
        } elseif (is_string($value)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * Get the validation error message.
     *
     * @return string
     */
    public function message()
    {
        // find locale string
        $attr_name = $this->normalizeAttributeName();

        return trans(self::VALIDATION_LOCALE_KEY, [
            'attribute' => $attr_name
        ]);
    }

    /**
     * @return array|\Illuminate\Contracts\Translation\Translator|null|string
     */
    private function normalizeAttributeName()
    {
        $trans_key = "validation.attributes.{$this->attribute}";
        $attr_name = trans($trans_key);

        // if no locale, use attribute name as default
        if ($attr_name === $trans_key) {
            $attr_name = $this->attribute;
        }

        return $attr_name;
    }

    public function limitSize(int $kb): self
    {
        $this->limit_size = $kb;

        return $this;
    }

    /**
     * @param array|string[] $extensions
     *
     * @return ImageFile
     */
    public function limitExtensions(array $extensions): self
    {
        $this->limit_extensions = array_map('strtolower', $extensions);

        return $this;
    }

    /**
     * @param array|string[] $extensions
     *
     * @return ImageFile
     */
    public function exceptExtensions(array $extensions): self
    {
        $this->except_extensions = array_map('strtolower', $extensions);

        return $this;
    }

    /**
     * @param $value
     *
     * @return bool
     */
    private function isFileSizeInLimit(UploadedFile $value): bool
    {
        return ($value->getSize() / 1024) <= $this->limit_size;
    }

    /**
     * @param $value
     *
     * @return bool
     */
    private function isFileTypeInLimit(UploadedFile $value): bool
    {
        return in_array(strtolower($value->guessClientExtension()), $this->limit_extensions);
    }

    /**
     * @param $value
     *
     * @return bool
     */
    private function isFileTypeInExcept(UploadedFile $value): bool
    {
        return in_array(strtolower($value->guessClientExtension()), $this->except_extensions);
    }
}
